﻿/*
 *  PassBag is multi-platform software that securely manage/store passwords
 *  Copyright (C) <2009>  <Hugo Rodrigues PEREIRA>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *	
 *  You can find a copy of the GPLv3 at project <root directory>/gpl.txt
 *
 */

using System;
using System.Security.Cryptography;
using System.Text;

namespace PassBag.Logic.Crypt {
    /// <summary>
    /// EncryptStringToBytes and decrypt strings and output hexadecimal string
    /// </summary>
    public class EncryptString {

        #region public variables
        //default de/encryption class
        public static EncryptString Default;
        #endregion

        #region private variable

        //encrypt algorithm
        private ICryptoTransform _encryption;
        private ICryptoTransform _decryption;
        private SymmetricAlgorithm _encryptAlgo;

        //string encoding
        private Encoding _stringEncoding;
        #endregion

        #region Constructors

        public EncryptString (string key)
            : this (key, SymetrycAlgoHelper.Encoding) {
        }

        public EncryptString (string key, Encoding encoding) :
            this (SymetrycAlgoHelper.Create (key, encoding), encoding) {
        }

        public EncryptString (SymmetricAlgorithm cryptAlgo, Encoding encoding) {
            StringEncoding = encoding;
            EncryptAlgo = cryptAlgo;
        }

        #endregion

        #region Public properties

        /// <summary>
        /// The string encoder
        /// </summary>
        /// <exception cref="ArgumentNullException">ArgumentNullException is raised if encoder is null</exception>
        public Encoding StringEncoding {
            get {
                return _stringEncoding;
            }
            set {
                if (value == null) {
                    throw new ArgumentNullException ("Encoding parameter null");
                }
                _stringEncoding = value;
            }
        }

        /// <summary>
        /// Symmetric encryption algorithm.
        /// </summary>
        /// <exception cref="ArgumentNullException">ArgumentNullException is raised if SymericAlgorith is null</exception>
        public SymmetricAlgorithm EncryptAlgo {
            get {
                return _encryptAlgo;
            }
            set {
                if (value == null) {
                    throw new ArgumentNullException ("symAlgo");
                }
                _encryptAlgo = value;
                _encryption = _encryptAlgo.CreateEncryptor ();
                _decryption = _encryptAlgo.CreateDecryptor ();
            }
        }

        #endregion

        #region Byte and string encrypt/decrypt

        private byte[] EncryptStringToBytes (string encryptString) {
            byte[] bytesToCrypt = _stringEncoding.GetBytes (encryptString);
            return _encryption.TransformFinalBlock (bytesToCrypt, 0, bytesToCrypt.Length);
        }

        private string DecryptBytesToString (byte[] decryptString) {
            return _stringEncoding.GetString (_decryption.TransformFinalBlock (decryptString, 0, decryptString.Length));
        }

        public string EncryptStringToHexString (string encryptString) {
            if (string.IsNullOrEmpty(encryptString)) {
                return string.Empty;                
            }
            else {
                return SymetrycAlgoHelper.ToHexString (EncryptStringToBytes (encryptString));
            }
        }

        public string DecryptHexStringToString (string decryptString) {
            if (string.IsNullOrEmpty (decryptString)) {
                return string.Empty;   
            }
            else {
                return DecryptBytesToString (SymetrycAlgoHelper.FromHexString (decryptString));
            }
        }

        public byte[] BytesEncryptToBytes (byte[] encryptBytes) {
            return _encryption.TransformFinalBlock (encryptBytes, 0, encryptBytes.Length);
        }

        public byte[] BytesDecryptToBytes (byte[] decryptBytes) {
            return _decryption.TransformFinalBlock (decryptBytes, 0, decryptBytes.Length);
        }

        public string EncryptStringToBase64String (string encryptString) {
            return Convert.ToBase64String (EncryptStringToBytes (encryptString));
        }

        public string DecryptStringBase64String (string decryptString) {
            return DecryptBytesToString (Convert.FromBase64String (decryptString));
        }

        #endregion
    }
}
